public class Test {
    /**
     * 方法的使用：
     * 方法就是一个代码片段，类似于C语言的函数
     * 1.能够模块化的组织代码
     * 2.代码可以被重复使用，一份代码在多个位置都可以使用
     * 3.直接调用现有方法开发
     */
    /**
     *方法的定义：
     * 修饰符 + 返回值类型 + 方法名称（参数类型 形参）{
     *     方法体代码;
     *     return + 返回值
     * }
     * 注意事项：
     * 1.修饰符：现阶段直接使用public static固定搭配
     * 2.返回值类型：有过方法有返回值，返回值类型必须要与返回的实体类型一致
     * 如果没有返回值，则类型那里一定要写成void
     * 3.方法名字：采用小驼峰命名（第一个单词的首字母小写，之后的每个单词的首字母大写）
     * 4.参数列表：如果方法没有参数，()里什么都不用写，如果有参数，需要指定参数类型，多个参数之间使用逗号隔开
     * 5.方法体：方法内部要执行的语句
     * 6.java中，方法必须写在类当中
     * 7.java中，方法不能嵌套定义
     * 8.java中，编译是全局的，这点区别于c的从顶至底，所以方法的位置是任意的，也没有方法声明这一说
     */
    //示例一：实现一个函数，检测一个年份是否是闰年
//    public static boolean isLeapYear(int year){
//        if (((0 == year % 4)&&(0 != year % 100))||(0 == year % 400)){
//            return true;
//        }else {
//            return false;
//        }
//    }

    //示例二：实现一个两个整数相加的方法
//    public static int addNum(int x, int y){
//        return x + y;
//    }
    /**
     * 方法调用的执行过程：
     * 调用方法 -> 传递参数 -> 找到方法地址 -> 执行被调方法的方法体 -> 被调方法结束返回 -> 回到主调方法下继续往下执行
     * 当方法执行过程中，遇到了return的时候，方法就结束了，意味着该方法在栈上开辟的空间就没有了
     * 定义方法的时候，不会执行方法里面的代码，只有调用的时候才会执行
     * 一个方法可以被多次使用
     */

//    //代码示例一：计算两个整数的相加

//    public static int add(int x, int y){
//        System.out.println("调用方法中x = " + x + " y = " + y);
//        return x + y;
//    }
//
//    public static void main(String[] args) {
//        int a = 10;
//        int b = 20;
//        System.out.println("第一次调用方法之前");
//        int ret = add(a, b);
//        System.out.println("第一次调用方法之后");
//        System.out.println("ret = " + ret);
//
//        System.out.println("第二次调用方法之前");
//        ret = add(30, 50);
//        System.out.println("第二次调用方法之后");
//        System.out.println("ret = " + ret);
//
//    }

    //示例二：计算 1！ + 2！ + 3！ + 4！+ 5！

    //计算一个数的阶乘
//    public static int fac(int n){
//        int ret = 1;
//        for (int i = 1; i <= n; i++){
//            ret *= i;
//        }
//        return ret;
//    }
//
//    //计算阶乘之和
//    public static int facSum(int n){
//        int sum = 0;
//        for (int i = 1; i <= n; i++){
//            sum += fac(i);
//        }
//        return sum;
//    }
//
//    public static void main(String[] args) {
//        System.out.println("5！ = " + fac(5));
//        System.out.println("4！ = " + fac(4));
//        System.out.println("3！ = " + fac(3));
//
//        System.out.println();
//
//        System.out.println("5! + 4！ + 3！ +...+ 1！ = " + facSum(5));
//        System.out.println("4！ + 3！ +...+ 1！ = " + facSum(4));
//        System.out.println("3！ +...+ 1！ = " + facSum(3));
//    }

    /**
     * 实参和形参的关系：
     * 形参的名字可以任意取，对方法没有影响
     * 形参只是方法在定义时候需要借助的一个变量，用来保存方法在调用时传递过来的值
     * 实参的值拷贝到形参中，形参和实参是两个实体
     * 形参是实参的一份临时拷贝，在方法中遇到return之后，形参就释放了
     *
     */

    //代码示例：交换两个整型变量
//    public static void swap(int x, int y){
//        int tmp = x;
//        x = y;
//        y = tmp;
//        System.out.println("swap:x = " + x + " y = " + y);
//    }
//
//    public static void main(String[] args) {
//        int a = 10;
//        int b = 20;
//        swap(a, b);
//        System.out.println("main:a = " + a + " b = " + b);
//    }
    //运行结果
    //swap:x = 20 y = 10
    //main:a = 10 b = 20
    //可以看到，在swap函数交换之后，形参x和y的值发生了改变，但是实参的a，b还是交换之前的值
    //即是传值调用，没有交换成功
    //在c语言中，为解决该问题，使用实参的地址来解决，但java没有指针概念
    //a,b:
    //作用域：在方法里。
    //生命周期：在调用方法的时候床i教案，方法调用结束的时候销毁
    //内存：存储在栈上
    //java是不允许直接到栈上面拿取地址的

    //解决办法：传引用类型的参数（例如数组来解决问题）

//    public static void swap(int[] arr){
//        int tmp = arr[0];
//        arr[0] = arr[1];
//        arr[1] = tmp;
//    }
//
//    public static void main(String[] args) {
//        int[] arr = {10, 20};
//        swap(arr);
//        System.out.println("arr[0] = " + arr[0] + " arr[1] = " + arr[1]);
//    }

    //注意：没有返回值的方法，其方法的返回值类型必须是void类型

    /**
     *方法重载：
     * 在Java中，如果多个方法的名字相同，参数列表不同（数据类型，个数，顺序不同），则会称该几种方法被重载了
     * 补充：放回置的类型不影响重载
     * 注意：
     * 1.方法名必须相同
     * 2.参数列表必须不同，即参数的个数不同，参数的类型不同，参数的次序必须不同
     * 3.返回值的类型是否相同无关
     */

//    public static int add(int x, int y) {
//        return x + y;
//    }
//    public static double add(double x, double y){
//        return x + y;
//    }
//
//    public static void main(String[] args) {
//        System.out.println(add(2, 3));
//        System.out.println(add(5.2, 6.5));
//    }

    //注意：两个方法如果仅仅只是因为返回值类型不同，是不能构成重载的
//    public static int add(int x, int y){
//        return x + y;
//    }
//    public static double add(int x, int y){
//        return x + y;
//    }
////编译错误

    /**
     * 方法签名：在同一个作用域中不能定义两个相同名称的标识符，但为什么类中就可以
     * 定义方法名相同的方法呢？
     * 方法签名：是编译器编译修改过之后方法最终的名字。具体方式：方法全路径名 + 参数列表 + 返回值类型
     * 构成方法完整的名字
     */

//        public static int add(int x, int y) {
//        return x + y;
//    }
//    public static double add(double x, double y){
//        return x + y;
//    }
//
//    public static void main(String[] args) {
//        System.out.println(add(2, 3));
//        System.out.println(add(5.2, 6.5));
//    }

    /**
     * 上述代码在经过编译之后，使用JDK自带的javap反汇编工具查看， （javap - v 字节码文件名）可以查看，方法名的真正的名字
     */

    //递归：有递，有归，一定要有递归的结束条件，并且有接近结束条件的语句

    //递归求N的阶乘
//    public static int factor(int n){
//        if (n == 1){
//            return 1;
//        }else{
//            return n * factor(n - 1);
//        }
//    }
//
//    public static void main(String[] args) {
//        int n = 5;
//        int ret = factor(n);
//        System.out.println(ret);
//    }

    /**
     * 调用栈：
     * 1.方法调用的时候，会有一个“栈”这样的内存空间描述当前的调用关系，成为调用栈
     * 2.每一次的方法调用就成为一个“栈帧”，每个栈帧中包含了这次调用的参数是那些，返回到哪里继续执行等信息
     */

    //递归练习：按顺序打印一个数字的每一位（1234：打印出1 2 3 4）

//    public static void print(int n){
//        if (n < 10){
//            System.out.println(n);
//            return;
//        }
//        print(n / 10);
//        System.out.println(n % 10);
//
//    }

//    public static void print(int n){
//        if (n > 9){
//            print(n / 10);
//        }
//        System.out.println(n % 10);
//    }
//
//    public static void main(String[] args) {
//        int i = 1234;
//        print(i);
//    }

    //练习：递归求1 + 2 + 3 +...+ 10
//    public static int sum(int n){
//        if (n == 1){
//            return 1;
//        }
//        return n + sum(n - 1);
//    }
//
//    public static void main(String[] args) {
//        int n = 10;
//        System.out.println(sum(n));
//    }

    //递归练习：输入一个非负整数，返回组成它的数字之和，例如：输入1729
    //应该返回1 + 7 + 2 +9，它的和是19

//    public static int sum(int n){
//        if (n < 10){
//            return n;
//        }
//        return n % 10 + sum(n / 10);
//    }
//
//    public static void main(String[] args) {
//        int n = sum(1234);
//        System.out.println(n);
//    }

    //求斐波那契数列的第N项
//    public static int fib(int n){
//        if (n == 1 || n == 2){
//            return 1;
//        }
//
//        return fib(n - 1) + fib(n - 2);
//    }
//    public static void main(String[] args){
//        int ret = fib(40);
//        System.out.println(ret);
//    }

    //但是斐波那契数列并不适合用递归，因为会进行大量的重复计算
    //可以使用循环（迭代）的方式来求斐波那契数列问题
//    public static void main(String[] args) {
//        int num1 = 1;
//        int num2 = 1;
//        int cur = 0;
//        int n = 40;
//        for (int i = 3; i <= n; i++){
//            cur = num1 + num2;
//            num1 = num2;
//            num2 = cur;
//        }
//        System.out.println(cur);
//    }




















}
